/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.farent.solutions.plugins.stripes.hyperstripes.core;

import com.farent.solutions.plugins.stripes.hyperstripes.annotations.RenderKitNamespace;
import com.farent.solutions.plugins.stripes.hyperstripes.spi.RenderKit;
import com.farent.solutions.plugins.stripes.hyperstripes.ext.HyperStripesResourceServlet;
import com.farent.solutions.plugins.stripes.hyperstripes.ext.ServletInfo;
import com.farent.solutions.plugins.stripes.hyperstripes.ext.WebXMLParser;
import com.farent.solutions.plugins.stripes.hyperstripes.utils.ResourceUtil;
import com.farent.solutions.plugins.stripes.hyperstripes.utils.Utils;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;

/**
 *
 * @author user
 */
public class HyperStripesApplicationContext implements StripesApplicationContext {

    private ServletContext servletContext;
    private String applicationUrl;
    private Map<String, RenderKit> renderKits = new LinkedHashMap<String, RenderKit>();
    private Map<String, String> componentKeyMap = new LinkedHashMap<String, String>();
    private List<ServletInfo> servletInfos;

    @Override
    public void init() {
        addRenderKits(HyperStripesRenderKit.getInstance());
    }

    @Override
    public String getApplicationUrl() {
        return applicationUrl;
    }

    public HyperStripesApplicationContext(ServletContext servletContext) {
        this.servletContext = servletContext;
        initServletInfos();
    }

    private void initServletInfos() {
        try {
            InputStream webXMLStream = getWebXMLInputStream();
            WebXMLParser webXMLParser = new WebXMLParser(webXMLStream);

            servletInfos = webXMLParser.getAllServlets();
            if (servletInfos == null) {
                servletInfos = new ArrayList<ServletInfo>();
            }
        } catch (Exception ex) {
            Logger.getLogger(HyperStripesApplicationContext.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    private InputStream getWebXMLInputStream() {
        InputStream result = getServletContext().getResourceAsStream("/WEB-INF/web.xml");
        return new BufferedInputStream(result);
    }

    @Override
    public String getResourceLocation(String resource) {
        try {
            String servletPathForClass = getServletPathForClass(HyperStripesResourceServlet.class.getName());

            String folderPath = ResourceUtil.trimPathToFolders(servletPathForClass);

            StringBuilder builder = new StringBuilder();
            builder.append(folderPath);
            builder.append(resource);
            return builder.toString();
        } catch (Exception ex) {
            throw new RuntimeException(ex.toString());
        }
    }

    private String getServletPathForClass(String name) {
        for (int i = 0; i < servletInfos.size(); i++) {
            ServletInfo servletInfo = servletInfos.get(i);
            if (servletInfo.getClassName().equals(name)) {
                return servletInfo.getServletUrls().get(0);
            }
        }
        return null;
    }

    @Override
    public Map<String, String> getComponentKeyMap() {
        return componentKeyMap;
    }

    @Override
    public void setApplicationUrl(String appUrl) {
        this.applicationUrl = appUrl;
    }

    @Override
    public Map<String, RenderKit> getRenderKits() {
        return renderKits;
    }

    @Override
    public void addRenderKit(RenderKit renderKit) {
        renderKits.put(renderKit.getNamespace(), renderKit);
    }

    @Override
    public ServletContext getServletContext() {
        return servletContext;
    }

    private void addRenderKits(HyperStripesRenderKit instance) {
        addRenderKit(instance);
        List<Class> classesWithAnnotation =
                ComponentAnnotationProcessor.getInstance().
                getClassesWithAnnotation(RenderKitNamespace.class);
        for (Class classWithAnnotation : classesWithAnnotation) {
            if (!classWithAnnotation.getName().
                    equalsIgnoreCase(HyperStripesRenderKit.class.getName())) {
                try {
                    RenderKitNamespace annotation = (RenderKitNamespace) classWithAnnotation.getAnnotation(
                            RenderKitNamespace.class);
                    RenderKit kit = (RenderKit) classWithAnnotation.newInstance();
                    renderKits.put(annotation.value(), kit);

                } catch (InstantiationException ex) {
                    Logger.getLogger(HyperStripesApplicationContext.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IllegalAccessException ex) {
                    Logger.getLogger(HyperStripesApplicationContext.class.getName()).log(Level.SEVERE, null, ex);
                }
            }

        }
    }

    @Override
    public RenderKit getRenderKit(String namespaceId) {
        for (Map.Entry<String, RenderKit> en : renderKits.entrySet()) {
            String key = en.getKey();
            RenderKit val = en.getValue();
            if (!Utils.nullOREmpty(key) && key.equalsIgnoreCase(namespaceId)) {
                return val;
            }
        }
        return null;
    }
}
